Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.

...powered by www.netzwerkartist.de...

Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Sprachbeschreibung
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Mathematisches
6 Eigene Klassen schreiben
7 Exceptions
8 Die Funktionsbibliothek
9 Threads und nebenläufige Programmierung
10 Raum und Zeit
11 Datenstrukturen und Algorithmen
12 Dateien und Datenströme
13 Die eXtensible Markup Language (XML)
14 Grafische Oberflächen mit Swing
15 Grafikprogrammierung
16 Das Netz
17 JavaServer Pages und Servlets
18 Verteilte Programmierung mit RMI und Web–Services
19 Applets, Midlets und Sound
20 Datenbankmanagement mit JDBC
21 Reflection und Annotationen
22 Komponenten durch Bohnen
23 Logging und Monitoring
24 Sicherheitskonzepte
25 Java Native Interface (JNI)
26 Dienstprogramme für die Java-Umgebung
A Die Begleit-DVD
Index

Download:
- ZIP, ca. 12,5 MB
Buch bestellen

Website zum Buch
Weblog des Autors
Ihre Meinung?

Spacer
 <<   zurück
Java ist auch eine Insel von Christian Ullenboom
Programmieren mit der Java Standard Edition Version 6
Buch: Java ist auch eine Insel

Java ist auch eine Insel
6., akt. und erw. Aufl., mit DVD
1.454 S., 49,90 Euro
Galileo Computing
ISBN 3-89842-838-9
gp 26 Dienstprogramme für die Java-Umgebung
  gp 26.1 Die Werkzeuge im Überblick
  gp 26.2 Java-Compiler
    gp 26.2.1 Bytecode Compiler javac
    gp 26.2.2 Native Compiler
    gp 26.2.3 Java-Programme in ein natives ausführbares Programm einpacken
  gp 26.3 Der Java-Interpreter java
    gp 26.3.1 Der Unterschied zwischen java.exe und javaw.exe
  gp 26.4 Das Archivformat Jar
    gp 26.4.1 Das Dienstprogramm Jar benutzen
    gp 26.4.2 Das Manifest
    gp 26.4.3 Applikationen in Jar-Archiven starten
    gp 26.4.4 Applets in Jar-Archiven
  gp 26.5 Monitoringprogramme
    gp 26.5.1 jps
    gp 26.5.2 jstat
    gp 26.5.3 jmap
    gp 26.5.4 jstack
  gp 26.6 Ant
    gp 26.6.1 Bezug und Installation von Ant
    gp 26.6.2 Properties
    gp 26.6.3 Externe und vordefinierte Properties
    gp 26.6.4 Weitere Ant-Tasks
  gp 26.7 Decompiler und Obfuscatoren
    gp 26.7.1 Der Decompiler Jad
    gp 26.7.2 Das Decompilieren erschweren
    gp 26.7.3 Das Obfuscator-Programm ProGuard
  gp 26.8 Sourcecode Beautifier
  gp 26.9 Zum Weiterlesen


Galileo Computing

26.7 Decompiler und Obfuscatoren  downtop

Ein Decompiler wandelt Java-Klassendateien in Java-Quellcodedateien zurück. Er verdreht also die Arbeitsweise eines Compilers, der aus der Quellcodedatei eine ausführbare Datei beziehungsweise Klassendatei erzeugt. Obwohl es für die verschiedensten Sprachen Decompiler gibt (unter anderem .NET, C und Smalltalk), ist für Java die Zurückübersetzung relativ einfach. Der Java-Compiler erstellt für einen virtuellen Prozessor Bytecode, und dieser Bytecode enthält viele wertvolle Informationen, die in einem herkömmlichen Maschinencode nicht auftauchen. Darunter sind etwa Typinformationen oder Hinweise, ob ein Methodenaufruf virtuell ist oder nicht. Sie sind für den Interpreter ebenfalls wichtig, um Programme als sicher oder unsicher zu erkennen. Dies macht es einfach, verlorenen Quellcode wiederzubeleben oder an fehlende Informationen aus Paketen von Fremdherstellern zu gelangen.

Ein weiteres Anwendungsgebiet sind Optimierungen am Quellcode. Über die Rückübersetzung lässt sich die Arbeitsweise eines Compilers gut verstehen, und wir können an einigen Stellen optimieren, wenn wir beispielsweise sehen, dass eine Multiplikation mit der Zahl 16 doch nicht zu einem Shift optimiert wurde. Das Übersetzen ist dabei verhältnismäßig einfach. Ein Decompiler benötigt lediglich die Klassendatei, wobei einige Decompiler auch direkt einen Verbund von Klassen aus einem Jar-Archiv unterstützen. Aus dem Java-Bytecode für eine Methode baut der Decompiler dann einen Kontrollfluss-Graphen auf und versucht, Ausdrücke zu erkennen, die bei der Übersetzung bestimmter Sprachkonstrukte entstanden sein müssten. Da Variablennamen durch einen Obfuscator eventuell ungültig gemacht worden sind, muss ein guter Decompiler diese illegalen Bezeichnernamen korrigieren. Somit sollte der Quelltext auch noch gut lesbar sein, obwohl er verunstaltet wurde. Diese Umbenennung ändert den Algorithmus nicht, und ein Decompiler hat es bei dieser Art von Verschleierung einfach. Es sind allerdings andere Techniken in der Entwicklung, die den Bytecode erst zur Laufzeit entschlüsseln, und dieser ist dann in der Klassendatei nicht mehr lesbar.

Da mittlerweile auch andere Compiler auf dem Markt sind, die Java-Bytecode erzeugen – etwa aus EIFFEL-Programmen oder aus diversen LISP-Dialekten –, ist über den Umweg Compiler/Klassendatei/Decompiler ein Crosscompiling denkbar. Hier sind jedoch einige Einschränkungen bezüglich der auf dem Markt befindlichen Decompiler erkennbar. Denn fremde Compiler, die Java-Bytecode erstellen, haben andere Techniken, die der Decompiler dann nicht immer passend übersetzen kann.

Ist das Decompilieren legal?

Lassen wir einen Decompiler auf den eigenen Programmcode los, weil etwa der Quellcode verschwunden ist, dann ist die Anwendung kein rechtliches Problem. Das Reverse Engineering von vollständigen Anwendungen, die unter Urheberschutz stehen, muss nicht unbedingt ein Problem darstellen. Vielmehr beginnt die Straftat, wenn dieser Quelltext verändert und als Eigenleistung verkauft wird.


Galileo Computing

26.7.1 Der Decompiler Jad  downtop

Jad (von Java Decompiler) ist ein frei verfügbarer Decompiler von Pavel Kouznetsov und oft [Das Kalkül der Anbieter von freiem Webspace besteht darin, immer nur Seiten anzubieten, die niemand kennt. Immer dann, wenn eine Seite bekannt ist und oft aufgerufen wird, muss der Freespacer tiefer in die Tasche greifen. Dann macht er die Seite einfach mit einer netten Meldung »The Tripod page you are trying to reach has exceeded its hourly bandwidth limit. The site will be available again in 2 hours!« dicht. ] unter der folgenden Adresse zu beziehen: http://www.kpdus.com/jad.html. Jad ist in C++ geschrieben [Wollte der Autor verhindern, dass auch sein Tool entschlüsselt wird? ] und decompiliert die Dateien sehr schnell. Bedauerlicherweise hat der Autor die Entwicklung von Jad eingestellt und möchte auch den Quellcode nicht freigeben, um eine Weiterentwicklung zu ermöglichen.

Da Jad auf jeden Fall den Bytecode auseinander nehmen muss, lässt sich zum Disassemblieren der Java-Bytecode auch in den Quellcodezeilen einblenden; eine prima Möglichkeit, Bytecode zu lernen und zu sehen, wie der Compiler funktioniert. Einen weiteren Pluspunkt bekommt Jad im Umgang mit Klassendateien, die ein Obfuscator [Ein Obfuscator benennt Methoden- und Klassennamen in unsinnige Bezeichner um. Er verschlüsselt Zeichenketten und versucht, im Code solche Bytecode-Kombinationen einzubauen, die von einem normalen Decompiler nicht wieder umgewandelt werden können. ] (leicht) verunstaltete. Daraus wird wieder gültiger Java-Code erzeugt. Manchmal muss Jad aber auch aufgeben, und dann verschwinden beispielsweise Zuweisungen.

Vom Download zur Installation

Jad liegt zurzeit in der Version 1.5.8 vor. Obwohl Jad im Quelltext nicht existiert, ist die Unterstützung von verschiedenen Betriebssystemen gewährleistet, unter anderem von Windows 9x/NT/2000, Linux und Mac OS X auf Intel Plattformen.

Das Programm ist schnell geladen und ebenso schnell entpackt. Danach offenbaren sich zwei Dateien, eine ausführbare Datei namens jad.exe (Windows 95/NT) oder jad (Unix) sowie eine Liesmich-Datei readme.txt, die eine kurze Anleitung für Jad enthält. Eine grafische Oberfläche wie FrontEnd Plus vereinfacht die Anwendung noch weiter, da sie zusammen mit Jad in einem leicht zu nutzenden Windows-Programm daherkommt. Unter http://jadclipse.sourceforge.net/ ist auch ein Plugin für Eclipse erhältlich. Doch bleiben wir bei der Kommandozeile.

Jad benutzen

Um eine Klassendatei zu decompilieren, wird Jad einfach auf diese Datei losgelassen:

$ jad example1.class

Ohne zusätzliche Option legt Jad eine Datei example1.jad im Arbeitsverzeichnis an. Jad verwendet nicht den Namen der Datei als Ausgabe, sondern den Namen der Klasse. Enthält also example1.class keine Klasse mit dem Namen example1, sondern mit dem Namen expl1, so heißt die Datei auch expl1.jad und nicht example1.jad. Existiert schon eine Datei dieses Namens, dann fragt Jad vorher nach, ob sie überschrieben werden kann. Die Option -o überschreibt, ohne zu fragen. Jad lässt auch Wildcards zum Aussortieren der Dateien zu. Ist der Standardname nicht sinnvoll, so lässt sich über den Schalter -s eine andere Extension erzeugen. Statt der Endung jad legen wir im folgenden Beispiel .java fest:

$ jad -sjava example1.class

Beim gleichzeitigen Verwenden der beiden Schalter -o und -sjava muss darauf geachtet werden, dass Jad beim Experimentieren die ursprüngliche Quelldatei nicht überschreibt.

Soll Jad alle Java-Klassen eines ganzen Dateibaums decompilieren, eignet sich dafür der Schalter -r. Denn dieser erstellt auch Unterverzeichnisse im angegebenen Stammverzeichnis (Option -d):

$ jad -o -r -sjava -dsrc tree/**/*.class        (WIN) 
$ jad -o -r -sjava -dsrc 'tree/**/*.class'      (Unix)

Gibt es also in der Datei tree/a/b/c.class die Klasse »c« vom Paket a.b, dann geht die Ausgabe in src/a/b/c.java.

Optionen der Kommandozeile

Die Optionen sind in der folgenden Tabelle zusammengestellt. Alle Optionen mit Ein-/Ausschaltcharakteristik lassen sich in drei Kategorien einteilen:

  • -o: Negiert den Wert der Option.
  • -o+: Setzt den Wert auf »wahr« oder »an«.
  • -o-: Setzt den Wert auf »falsch« oder »aus«.

Tabelle 26.4    Schalter von Jad
Schalter Wirkung
-a JVM-Bytecode wird als Kommentar in den Quelltext mit eingesetzt.
-af Wie -a, nur mit voll qualifiziertem Namen
-b Redundante Klammern um Anweisungen, standardmäßig aus. Beispiel: if(a) { b(); }
-disass Nur den Bytecode disassemblieren ohne Quellcodeerzeugung
-d <dir> Verzeichnis der Ausgabedateien (wird – wenn erforderlich – auch angelegt)
-f Voll qualifizierte Namen für Klassen, Variablen und Methoden überall im Quelltext verwenden
-i Initialisiert alle nicht finalen Variablen
-l <num> Teilt einen String in zwei Hälften, wenn er länger als <num> ist; nicht voreingestellt
-nl Strings mit Newline-Zeichen aufspalten; nicht voreingestellt
-o Ausgabedatei überschreiben
-p Code in die Standardausgabe lenken, sinnvoll fürs Pipen
-r Verzeichnisstruktur vom Paket erhalten
-s <ext> Endung der Ausgabedateien bestimmen
-t Tabulatoren statt Leerzeichen zum Einrücken verwenden
-t <num> Breite der Einrückungen; voreingestellt sind vier Leerzeichen
-v Zeigt zur Kontrolle die decompilierten Methodennamen
–8 Unicode-String in 8-Bit-Strings nach der ANSI-Code-Tabelle (nur Win32) umwandeln


Galileo Computing

26.7.2 Das Decompilieren erschweren  downtop

Obwohl wir Decompilierung verhindern können, ist es noch immer nicht möglich, das bloße Disassemblieren des Bytecodes zu stören. Es gibt allerdings einige einfache Tipps, die dem motivierten Angreifer schnell die Lust am Bytecode verderben. Wir beschreiben einige Regeln, die das Entschlüsseln von Bytecode oder das Umgehen einer Seriennummerneingabe erschweren. Dazu gehören folgende Maßnahmen:

  • Verwendung von Methodennamen und Klassennamen aus Nullen, dem Buchstaben O, Einsen und dem Buchstaben l. Einige freie Obfuscatoren lassen sich leicht anpassen, sodass sie solche Bezeichner erstellen.
  • Im Quellcode sollten keine lesbaren Zeichenketten vorkommen. Daher fügen wir jeder Klasse eine individuelle Entschlüsselungsfunktion hinzu. Bessere Obfuscator-Programme machen das automatisch.
  • Mathematische Funktionen berechnen die Werte von Konstanten. Erwartet das Programm zum Beispiel die Taste KeyEvent.VK_F1, wird der Compiler automatisch für die Konstante den Wert 0x70 einsetzen. Natürlich können wir diesen Wert auch dynamisch berechnen.
  • Verwendung vieler bedingter Sprünge, die aber unnütz sind.
  • Wenn die Möglichkeit besteht, den Bytecode direkt zu manipulieren, können legale, doch unsinnige Bytecode-Sequenzen eingefügt werden. Dynamischer Java-Bytecode hat sich (noch) nicht durchgesetzt, wäre aber möglich. Denkbar ist, an bestimmten Stellen einer Klassendatei Zeichen zu schreiben, dann diese Datei über den Klassenlader zu laden und die Information anschließend wieder zurückzuschreiben. An der »bestimmten Position« könnte etwa eine Variable stehen.
  • Teile des Programmcodes sollten auf dynamisch berechnet Tabellen zurückgreifen.
  • Ein Startbildschirm mit Grafik und Text (Splash-Screen beziehungsweise Nag-Screen) kann leicht zurückverfolgt werden. Daher sollte besser darauf verzichtet werden.
  • Bei einer Seriennummer und einem Ablaufdatum lässt sich die Systemzeit natürlich zurücksetzen. Wir können kontinuierlich ein Datum verschlüsselt in eine Datei schreiben und dieses ständig erhöhen. Ist das Datum des Rechners kleiner als das Datum in der Datei, hat der Benutzer zu schummeln versucht. Ein alternativer Weg ist plattformabhängig: Einige Systemdateien weisen das Datum vor dem Zurückstellen auf, wie etwa SYSTEM.DAT.
  • Bei Seriennummern sucht der Angreifer nach Texteingabefeldern. Besser ist in diesem Fall eine Lowlevel-Event-Verarbeitung. Wir legen einen Listener zum Beispiel auf etwas ganz anderes, beispielsweise ein Label. Die Ereignisse werden abgefangen und bearbeitet. Aus dem AWT-Event holen wir dann die Zeichen heraus. Da der Angreifer aber auch nach Eventhandlern sucht, ließe sich auch die System-Queue abhorchen.
  • Checksummen von Klassen bilden, die eventuell angezapft werden könnten. In einer anderen Klasse lässt sich dann diese Checksumme testen. Zum Entschlüsseln von Daten können auch weitere Klassendateien verwendet werden.

Nun mein Lieblingstipp: Zeitmessungen vornehmen, um zu erkennen, ob jemand versucht, das Programm zu debuggen. Zudem lassen sich Cracker leicht befriedigen, indem ihnen eine offensichtliche Prüfung einer eingegebenen Seriennummer angeboten wird. An weiteren Stellen können aber ein Test auf die Seriennummer und subtile Fehlfunktionen ins Programm eingewoben sein. Das Programm hat kleine Fehler oder Unzulänglichkeiten, falls die Seriennummer diese Tests noch nicht erfüllt.


Galileo Computing

26.7.3 Das Obfuscator-Programm ProGuard  toptop

ProGuard (http://proguard.sourceforge.net/) ist ein Open-Source-Projekt unter der GPL-Lizenz [Obwohl ProGuard selbst unter GPL steht, darf die Software auch angewendet werden auf Software, die nicht unter der GPL stehen. ] , das Java-Klassen und Jar-Archive verschleiert. Es bietet eine ganze Reihe von Versteck-Aktionen:

  • Löscht Debug-Informationen.
  • Benennt Bezeichner für alle Pakete um und gestaltet sie für neugierige Augen ermüdend. Klassen heißen dann zum Beispiel C1, C2, . und Methoden m1, m2, .
  • Vereinfacht Bytecode-Sequenzen.

Neben der Verschleierung ist ein Nebeneffekt, dass die Klassendateien kleiner werden, was insbesondere für Applets und Midlets (mobile Anwendungen) interessant ist. ProGuard 3 bietet Unterstützung für das Bytecode Format von Java 5 und Java ME – ProGuard 4 bietet Obfuscation auch für Java 6. Die Software lässt sich über eine Swing-Oberfläche oder über die Kommandozeile bedienen oder aber auch über ein Ant-Skript steuern. Die Webseite nennt ein Beispiel, mit dem alle Typen bis auf Applets eines Java-Archivs berücksichtigen. Auf der Kommandozeile ist anzugeben:

$ java -jar proguard.jar -injars in.jar -outjars out.jar -libraryjars ð 
$JAVA_HOME/lib/rt.jar -keep public class * extends java.applet.Applet


Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.





 <<   zurück



Copyright © Galileo Press 2007
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de